home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 001-025 / scopedisk14 / cc / cc.c next >
Text File  |  1995-03-18  |  25KB  |  807 lines

  1. /************************************************************************
  2.  *                                    *
  3.  *            Copyright (c) 1985, Fred Fish            *
  4.  *                All Rights Reserved                *
  5.  *                                    *
  6.  *    This software and/or documentation is released into the        *
  7.  *    public domain for personal, non-commercial use only.        *
  8.  *    Limited rights to use, modify, and redistribute are hereby    *
  9.  *    granted for non-commercial purposes, provided that all        *
  10.  *    copyright notices remain intact and all changes are clearly    *
  11.  *    documented.  The author makes no warranty of any kind with    *
  12.  *    respect to this product and explicitly disclaims any implied    *
  13.  *    warranties of merchantability or fitness for any particular    *
  14.  *    purpose.                            *
  15.  *                                    *
  16.  ************************************************************************
  17.  */
  18.  
  19.  
  20. /*
  21.  *    cc -- C compiler front end for Amiga and Lattice C.
  22.  *
  23.  *    Somewhat AMIGA/Lattice dependent, but can probably be adapted to
  24.  *    other systems with a minimum of work.  I have attempted to keep
  25.  *    portability in mind as much as possible.
  26.  *
  27.  *    Changes by mwm:    (look for comments tagged mwm)
  28.  *        1) Change link lib for 3.03.
  29.  *        2) Fix abortion for 3.10, which does it better.
  30.  *        3) Comment on what all flags do.
  31.  *        4) Add rest of 4.3BSD flags (well, 4.3beta).
  32.  *        5) Move Amiga-specific flags to -A
  33.  *        6) Use INCLUDE: instead of searching for include directory.
  34.  *        7) Change ALINK to BLINK (as per 3.10)
  35.  *        8) Define LATTICE at compile time.
  36.  *        9) Add -A flags for SMALLCODE, SMALLDATA, and disabling stack
  37.  *            checking
  38.  *        10) Implement the -g flag.
  39.  *        11) LIB: is now searched last for libraries, and
  40.  *        12) LC: is now searched last for commands.
  41.  *        13) Add code to handle objects landing in specific memory.
  42.  *        14) Add -. to turn off copyright messages.
  43.  *    And now the changes for 4.0:
  44.  *        15) Change default quad device to QUAD:.
  45.  *        16) Turn off source in error messages
  46.  *        17) Turn off warnings about structures as function args
  47.  *        18) Turn on cheks for real prototypes.
  48.  *        19) Add -Ap to turn off prototype checking.
  49.  *        20) Add -Af to use motorola FFP instead of IEEE.
  50.  *        21) Add -As to get source listings out anyway.
  51.  *        22) Add prototypes and include string.h
  52.  */
  53.  
  54. char _sccsid[] = "@(#)cc.c    1.8";
  55.  
  56. #include <stdio.h>
  57. #include <string.h>
  58.  
  59. /*
  60.  *    The following allow use on systems that don't have my macro based
  61.  *    debugging package.  The default, for now, is to assume it is not
  62.  *    available.
  63.  */
  64.  
  65. #ifdef DBUG
  66. #  include <local/dbug.h>
  67. #else    /* !DBUG */
  68. #  define DBUG_ENTER(a)
  69. #  define DBUG_RETURN(a) return(a)
  70. #  define DBUG_VOID_RETURN return
  71. #  define DBUG_2(a,b)
  72. #  define DBUG_3(a,b,c)
  73. #  define DBUG_4(a,b,c,d)
  74. #  define DBUG_5(a,b,c,d,e)
  75. #  define DBUG_PUSH(a)
  76. #endif    /* DBUG */
  77.  
  78. /*
  79.  *    IMPLEMENTATION NOTES
  80.  *
  81.  *    Some of the builtin (artificial) limits could be removed by
  82.  *    using dynamically allocated data structures, such as keeping the
  83.  *    operand list as a linked list with space for each link supplied
  84.  *    by malloc.  This would certainly increase the code space, while
  85.  *    reducing the statically allocated data space.  The net result
  86.  *    would probably be a program requiring about the same amount of
  87.  *    total memory for most day to day usages.  When source is not
  88.  *    available to the end user, maximum flexibility is a must and
  89.  *    dynamic allocation is the only way to go.  In this case however
  90.  *    it is not clear that the added complexity is worth it, since
  91.  *    source should be available for anyone wishing to expand the
  92.  *    limits.
  93.  *
  94.  *    One last note, if you are going to have builtin limits then
  95.  *    check the @#$%&* things for overflow.  Running off the end of
  96.  *    an array with no indication that something is wrong, other
  97.  *    than a crash, if definitely unfriendly!
  98.  *
  99.  */
  100.  
  101. /*
  102.  *    Manifest constants which can be tuned to fit requirements.
  103.  */
  104.  
  105. #define CMDBUFFERSIZE (1024)    /* Size of command buffer for CLI command */
  106. #define MAXOPERANDS (64)    /* Maximum number of operands on cmd line */
  107. #define MAXDEFINES (32)        /* Maximum number of -D<name> args */
  108. #define MAXUNDEFINES (32)    /* Maximum number of -U<name> args */
  109. #define MAXINCDIRS (16)        /* Maximum number of -I<filename> args */
  110. #define MAXLIBS (16)        /* Maximum number of -l<lib> args */
  111. #define ARGSIZE (64)        /* Size of temp args for cmd line */
  112.  
  113. /*
  114.  *    Define QUADDEV to be the default place where you want the compiler
  115.  *    intermediate files (quad files) to be created. As of 4.0, we follow
  116.  *    Lattice in making this be the QUAD: assigned name. Most of the time,
  117.  *    it'll work fine in ram:, but large compiles may want it on a disk.
  118.  *    In either case, the default can be overridden with the -q option.
  119.  */
  120.  
  121. #define QUADDEV    "QUAD:"        /* Keep intermediate files in assigned place */
  122. /* #define QUADDEV "ram:" */    /* Keep intermediate files in ram: */
  123. /* #define QUADDEV "" */    /* Keep intermediate files in current dir */
  124.  
  125. /*
  126.  *    Manifest constants which are generally the same on all systems.
  127.  */
  128.  
  129. #define EOS '\000'        /* End of string character */
  130.  
  131. /*
  132.  *    Command line arguments that represent files to be compiled, assembled,
  133.  *    or linked, are kept track of via an "Operand" array.  If, for example,
  134.  *    the file name is "df0:mydir/junk.c", then the Rootname is
  135.  *    "df0:mydir/junk", the Basename is "junk", and the Suffix is "c".
  136.  *    String suffixes are used, rather than single character suffixes, to
  137.  *    allow use of names with multicharacter suffixes.
  138.  */
  139.  
  140. struct Operand {        /* Info about each operand (non option) */
  141.     char *Rootname;        /* Name minus any suffix */
  142.     char *Basename;        /* Name minus any prefix or suffix */
  143.     char *Suffix;        /* Suffix of operand */
  144. };
  145.  
  146. static struct Operand Operands[MAXOPERANDS];    /* Table of operands */
  147. static int NOperands = 0;            /* Number of operands found */
  148. static char *Defines[MAXDEFINES];        /* Table of defines */
  149. static int NDefines = 0;            /* Number of defines */
  150. static char *UnDefines[MAXUNDEFINES];        /* Table of undefines */
  151. static int NUnDefines = 0;            /* Number of undefines */
  152. static char *UserInc[MAXINCDIRS];        /* Table of include dirs */
  153. static int NUserInc = 0;            /* Number of include dirs */
  154. static char *Libs[MAXLIBS];            /* Table of library args */
  155. static int NLibs = 0;                /* Number of library args */
  156.  
  157. /*
  158.  *    The command line buffer for child commands is allocated statically,
  159.  *    rather than as an automatic, to forstall problems with stack limits
  160.  *    in initial implementations.  Hopefully, automatic stack growth will
  161.  *    be implemented in future release of the C compiler.  If nothing
  162.  *    else, someday I will read the manuals and figure out how to explicitly
  163.  *    grow the stack...
  164.  *
  165.  */
  166.  
  167. static char Command[CMDBUFFERSIZE];        /* Command line buffer */
  168. static char *EndCommand = Command;        /* End of current command */
  169.  
  170. /*
  171.  *    Macros to determine the suffix type of a file given a pointer to
  172.  *    its operand structure.
  173.  */
  174.  
  175. #define CFILE(op) (strcmp(op->Suffix,"c")==0)
  176. #define SFILE(op) (strcmp(op->Suffix,"s")==0)
  177. #define OFILE(op) (strcmp(op->Suffix,"o")==0)
  178.  
  179. /*
  180.  *    Now some macros to enable abort on control-C.
  181.  */
  182. #  define CHECKABORT
  183.  
  184. /*
  185.  *    Set list of places to search for various executables, libraries, etc.
  186.  *    Searched in order, first match wins, null string is current directory.
  187.  *    Note that these names are used as prefixes exactly as given, so
  188.  *    device names must end in ':' and directory names must end in '/'.
  189.  *
  190.  */
  191.  
  192. static char *BinDirs[] = {
  193.     "",
  194.     "LC:",
  195.     NULL
  196. };
  197.  
  198. static char *LibDirs[] = {
  199.     "",
  200.     "LIB:",
  201.     NULL
  202. };
  203.  
  204. /*
  205.  *    Flags set by command line arguments/
  206.  */
  207.  
  208. static int cflag;            /* -c flag given */
  209. static int Pflag;            /* -P flag given */
  210. static int Sflag;            /* -S flag given */
  211. static int gflag;            /* -g flag given */
  212. static int Vflag;            /* -V flag given (non-standard) */
  213. /* Amiga specific flags */
  214. static int scflag;            /* -Ac flag given */
  215. static int sdflag;            /* -Ad flag given */
  216. static int FFPflag;            /* -Af flag given */
  217. static int protoflag;            /* -Ap flag given */
  218. static int shortflag;            /* -As flag given */
  219. static int Avflag;            /* -Av flag given */
  220. static int Ayflag;            /* -Ay flag given */
  221. static int ACflag;            /* -AC flag given */
  222. static int ADflag;            /* -AD flag given */
  223. static int ABflag;            /* -AB flag given */
  224. static int sourceflag;            /* -AS flag given */
  225.  
  226. static int ErrCount = 0;        /* Count of compile/assemble errors */
  227. static char *outfile = "a.out";        /* Output file name from linker */
  228. static char *QuadDev = QUADDEV;        /* Where to keep quad files */
  229.  
  230. static char *Locate (char *, char **);    /* Find a file */
  231. static void AddToCommand (char *, );    /* Add argument to command buffer */
  232. static void InitCommand (void);        /* Initialize command buffer */
  233. static void Fatal (char *, );        /* Quit  with fatal error */
  234. static void Warning (char *, );        /* Issue warning message */
  235. static void AddOperandToList (char *);    /* Add .c, .s, or .o file to list */
  236. static void CleanObjects (void);    /* Remove .o for link and go mode */
  237. static void MakeObjects (void);        /* Reduce to list of object files */
  238. static void ParseCommandLine (int, char **);
  239.                     /* Deal with command line */
  240. static void Compile (struct Operand *);    /* Translate from .c to .o */
  241. static void Assemble (struct Operand *);/* Translate from .s to .o */
  242. static void Link (void);        /* Gather .o's into executable */
  243. static int Pass1 (struct Operand *);    /* Pass 1 of the compiler */
  244. static int Pass2 (struct Operand *);    /* Pass 2 of the compiler */
  245. static int RunCommand (void);        /* Run a command */
  246. static int Readable (char *);        /* Check to see if a file is readable */
  247. extern void exit (int);            /* See exit(2) */
  248. extern int system (char *);        /* See system(2) */
  249.  
  250. /*
  251.  *    Main entry point.  Note that despite common usage where main is
  252.  *    essentially of type void, we declare it explicitly to return
  253.  *    an int, and actually return a value.  In most implementations,
  254.  *    the value returned from main is the exit status of the program.
  255.  *    Whether this applies to Lattice C or not, I'm not sure yet.
  256.  */
  257.  
  258. int main (argc, argv)
  259. int argc;
  260. char **argv;
  261. {
  262.     DBUG_ENTER ("main");
  263.     ParseCommandLine (argc, argv);
  264.     MakeObjects ();
  265.     if (!cflag && !Pflag && !Sflag && ErrCount == 0) {
  266.     Link ();
  267.     CleanObjects ();
  268.     }
  269.     DBUG_RETURN (0);
  270. }
  271.  
  272. /*
  273.  *    The following macro is used to allow optional whitespace between
  274.  *    an option and it's argument.  Argp is left pointing at the option
  275.  *    and argv and argc are adjusted accordingly if necessary.
  276.  *
  277.  *    Note that there is no check for missing option arguments.  In
  278.  *    particular, -o -V will blindly take -V as the output file name.
  279.  *
  280.  */
  281.  
  282. #define XARG(argc,argv,argp) {if(*++argp==EOS){argp=(*argv++);argc--;}}
  283.  
  284. static void
  285. ParseCommandLine (argc, argv) int argc; char **argv;
  286. {
  287.     register char *argp;    
  288.  
  289.     DBUG_ENTER ("ParseCommandLine");
  290.     argc--;
  291.     argv++;
  292.     while (argc-- > 0) {
  293.     argp = *argv++;
  294.     if (*argp != '-') {
  295.         AddOperandToList (argp);
  296.     } else {
  297.         switch (*++argp) {
  298.         case '#':    /* For DBUG, I assume - mwm */
  299.             XARG (argc, argv, argp);
  300.             DBUG_PUSH (argp);
  301.             break;
  302.         case 'A':    /* Amiga flags, non-standard */
  303.             while (*++argp) {
  304.             switch (*argp) {
  305.                 case 'C':    /* Place code in chip ram */
  306.                     ACflag++;
  307.                 break;
  308.                 case 'D':    /* Place data in chip ram */
  309.                     ADflag++;
  310.                 break;
  311.                 case 'B':    /* Place BSS in chip ram */
  312.                        ABflag++;
  313.                 break;
  314.                 case 'S':    /* Turn source listing back on */
  315.                     sourceflag++ ;
  316.                 break ;
  317.                 case 'c':    /* Generate smallcode model */
  318.                 scflag++;
  319.                 break;
  320.                 case 'd':    /* Generate smalldata model */
  321.                 sdflag++;
  322.                 break;
  323.                 case 'f':    /* Use the Motorola FFP instead of IEEE */
  324.                 FFPflag++ ;
  325.                 break ;
  326.                 case 'p':    /* Turn off prototype checking */
  327.                 protoflag++ ;
  328.                 break ;
  329.                 case 'q':    /* Specify where quad file goes */
  330.                 XARG (argc, argv, argp);
  331.                 QuadDev = argp;
  332.                 goto NoMoreAmiga;
  333.                 case 's':    /* Short integers! */
  334.                 shortflag++ ;
  335.                 break;
  336.                 case 'v':    /* Disable stack checking */
  337.                 Avflag++;
  338.                 break;
  339.                 case 'y':    /* Load A6 with LinkerDB */
  340.                 Ayflag++ ;
  341.                 break ;
  342.             }
  343.             }
  344. NoMoreAmiga:        break;    /* Out of Amiga loop. Need multi-level break! */
  345.         case 'B':    /* Use backup compiler, possibly as specified */
  346.             break;        /* NOP for now */
  347.         case 'C':    /* Have cpp not elide comments */
  348.             break;        /* NOP for now */
  349.         case 'c':    /* Produce .o file, don't load */
  350.             cflag++;
  351.             break;
  352.         case 'D':    /* Define value for cpp */
  353.             XARG (argc, argv, argp);
  354.             if (NDefines >= MAXDEFINES) {
  355.             Fatal ("too many -D args (%d max)", MAXDEFINES);
  356.             }
  357.             Defines[NDefines++] = argp;
  358.             break;
  359.         case 'E':    /* Only run preprocessor, result to stdout */
  360.             Pflag++;
  361.             break;
  362.         case 'f':    /* Don't force auto-convert float to double */
  363.             break;    /* NOP for now, just eat it */
  364.         case 'g':    /* Produce debugging output */
  365.             gflag++;
  366.             break;
  367.         case 'I':    /* Add directory for include file searches */
  368.             XARG (argc, argv, argp);
  369.             if (NUserInc >= MAXINCDIRS) {
  370.             Fatal ("too many -I args (%d max)", MAXINCDIRS);
  371.             }
  372.             UserInc[NUserInc++] = argp;
  373.             break;
  374.         case 'L':    /* Search for libraries in specified dir */
  375.             break;        /* NOP for now */
  376.         case 'l':    /* another library to use at link time */
  377.             XARG (argc, argv, argp);
  378.             if (NLibs > MAXLIBS) {
  379.             Fatal ("too many -l args (%d max)", MAXLIBS);
  380.             }
  381.             Libs[NLibs++] = argp;
  382.             break;
  383.         case 'M':    /* Generate Makefile dependencies */
  384.             break;        /* NOP for now */
  385.         case 'O':    /* enable the optimizer */
  386.             break;        /* NOP for now, just eat it */
  387.         case 'o':    /* Name of output file */
  388.             XARG (argc, argv, argp);
  389.             outfile = argp;
  390.             break;
  391.         case 'p':    /* turn on the profiler */
  392.             break;        /* NOP for now */
  393.         case 'P':    /* Same as -E, for sysV compatability */
  394.             Pflag++;
  395.             break;
  396.         case 'R':    /* make initialized variables read-only */
  397.             break;        /* NOP for now */
  398.         case 'S':    /* Produce assmebler output */
  399.             Sflag++;
  400.             Warning ("-S option not yet implemented, ignored");
  401.             break;
  402.         case 's':    /* Some system V thingy, I suppose */
  403.             break;        /* NOP for now, just eat it */
  404.         case 't':    /* Specify which passes to use from -B */
  405.             break;        /* NOP for now */
  406.         case 'U':    /* Undefine the rest of the argument */
  407.             XARG (argc, argv, argp);
  408.             if (NUnDefines >= MAXUNDEFINES) {
  409.             Fatal ("too many -U args (%d max)", MAXUNDEFINES);
  410.             }
  411.             UnDefines[NUnDefines++] = argp;
  412.             break;
  413.         case 'V':    /* Verbose mode, dump actual commands */
  414.             Vflag++;
  415.             break;
  416.         case 'w':    /* Turn off warnG_ENTER ("MakeObjects");
  417.     for (index = 0; index < NOperands; index++) {
  418.     CHECKABORT;
  419.     op = &Operands[index];
  420.     if (NOperands > 1 && (CFILE (op) || SFILE (op))) {
  421.         printf ("%s.%s:\n", op -> Rootname, op -> Suffix);
  422.     }
  423.     if (CFILE (op)) {
  424.         Compile (op);
  425.     } else if (SFILE (op)) {
  426.         Assemble (op);
  427.     }
  428.     }
  429.     DBUG_VOID_RETURN;
  430. }
  431.  
  432. /*
  433.  *    Note that commands to cc of the form d)
  434. {
  435.     register int index;
  436.     register struct Operand *op;
  437.     register char *name;
  438.     auto char buffer[ARGSIZE];
  439.     
  440.     DBUG_ENTER ("Link");
  441.     CHECKABORT;
  442.     InitCommand ();
  443.     AddToCommand ("%s ", Locate ("blink", BinDirs));    /* 3.10 uses blink - mwm*/
  444.     /* Change Lstartup.obj to c.o for 3.03 -- mwm */
  445.     AddToCommand ("%s", Locate ("c.o", LibDirs));
  446.     for (index = 0; index < NOperands; index++) {
  447.     op = &Operands[index];
  448.     if (OFILE (op)) {
  449.         name = op -> Rootname;
  450.     } else {
  451.         name = op -> Basename;
  452.     }
  453.     AddToCommand ("+%s.o", name);
  454.     }
  455.     AddToCommand ("%s", " library ");
  456.     for (index = 0; index < NLibs; index++) {
  457.     sprintf (buffer, "%s.lib", Libs[index]);
  458.     AddToCommand ("%s+", Locate (buffer, LibDirs));
  459.     }
  460.     if (FFPflag) AddToCommand("%s+", Locate ("lcmffp.lib", LibDirs));
  461.     AddToCommand ("%s+", Locate ("lc.lib", LibDirs));
  462.     AddToCommand ("%s", Locate ("amiga.lib", LibDirs));
  463.     if (scflag) AddToCommand (" %s", "SC");
  464.     if (sdflag) AddToCommand (" %s", "SD");
  465.     if (gflag) AddToCommand (" %s", "ADDSYM");
  466.     AddToCommand (" %s", "ND BATCH");
  467.     AddToCommand (" to %s map nil:", outfile);
  468.     (void) RunCommand ();
  469.     DBUG_VOID_RETURN;
  470. }
  471.  
  472. /*VARARGS1*/
  473. static void
  474. Warning (fmt, arg1, arg2, arg3)
  475.     char *fmt, *arg1, *arg2, *arg3;
  476. {
  477.     fprintf (stderr, "cc -- warning: ");
  478.     fprintf (stderr, fmt, arg1, arg2, arg3);
  479.     fprintf (stderr, "\n");
  480.     (void) fflush (stderr);
  481. }
  482.  
  483. /*VARARGS1*/
  484. static void
  485. Fatal (fmt, arg1, arg2, arg3)
  486.     char *fmt, *arg1, *arg2, *arg3;
  487. {
  488.     fprintf (stderr, "cc -- fatal error: ");
  489.     fprintf (stderr, fmt, arg1, arg2, arg3);
  490.     fprintf (stderr, "\n");
  491.     (void) fflush (stderr);
  492.     exit (1);
  493. }
  494.  
  495. /*
  496.  *    Split an operand name into rootname, basename, and suffix
  497.  *    components.  The rootname is the full name, minus any suffix,
  498.  *    but including any prefix.  The basename is the rootname minus
  499.  *    any prefix.  The suffix is anything after the last '.' character.
  500.  *    Only the suffix is allowed to be the null string.
  501.  */
  502.  
  503. static void
  504. AddOperandToList (filename) char *filename;
  505. {
  506.     register char *split;
  507.     register struct Operand *op;
  508.     extern char *strrchr ();
  509.  
  510.     DBUG_ENTER ("AddOperandToList");
  511.     DBUG_3 ("ops", "add file '%s' to operand list", filename);
  512.     if (NOperands >= MAXOPERANDS) {
  513.     Fatal ("too many files (%d max)\n", MAXOPERANDS);
  514.     }
  515.     op = &Operands[NOperands];
  516.     op -> Rootname = filename;
  517.     if ((split = strrchr (filename, '/')) == NULL) {
  518.     split = strrchr (filename, ':');
  519.     }
  520.     if (split == NULL) {
  521.     op -> Basename = filename;
  522.     } else {
  523.     op -> Basename = ++split;
  524.     }
  525.     if ((split = strrchr (filename, '.')) == NULL) {
  526.     op -> Suffix = "";
  527.     } else {
  528.     *split++ = EOS;
  529.     op -> Suffix = split;
  530.     }
  531.     DBUG_3 ("ops", "rootname '%s'", op -> Rootname);
  532.     DBUG_3 ("ops", "basename '%s'", op -> Basename);
  533.     DBUG_3 ("ops", "suffix '%s'", op -> Suffix);
  534.     NOperands++;
  535.     DBUG_VOID_RETURN;
  536. }
  537.  
  538. /*
  539.  *    Compile one operand from a C source program to an object module.
  540.  */
  541.  
  542. static void
  543. Compile (op) struct Operand *op;
  544. {
  545.     DBUG_ENTER ("Compile");
  546.     CHECKABORT;
  547.     if (!Sflag && !Pass1 (op) && !Pflag) {        /* Order important! */
  548.     CHECKABORT;
  549.     (void) Pass2 (op);
  550.     }
  551.     DBUG_VOID_RETURN;
  552. }
  553.  
  554. /*
  555.  *    Note that because of brain-damage in the fact that -p to lc1 removes
  556.  *    all predefined defs, we must add them so replacing -c with -P in the
  557.  *    cc command line will result in the same set of predefined symbols.
  558.  *    This is rather ugly and leaves a hole for future problems if we
  559.  *    get out of sync with respect to what names the compiler predefines.
  560.  */
  561.  
  562. static int
  563. Pass1 (op) register struct Operand *op;
  564. {
  565.     register int status;
  566.     register int index;
  567.     
  568.     DBUG_ENTER ("Pass1");
  569.     CHECKABORT;
  570.     InitCommand ();
  571.     AddToCommand ("%s", Locate ("lc1", BinDirs));
  572.     if (Pflag) {
  573.     AddToCommand (" -o%s.i -p -DAMIGA -DM68000 -DSPTR -DLATTICE", op -> Basename);
  574.     } else {
  575.     AddToCommand (" -o%s%s.q", QuadDev, op -> Basename);
  576.     }
  577.     for (index = 0; index <NUserInc; index++) {
  578.     AddToCommand (" -i%s/", UserInc[index]);
  579.     }
  580.     for (index = 0; index <NUnDefines; index++) {
  581.     AddToCommand (" -u%s", UnDefines[index]);
  582.     /*************************
  583.     Warning ("-U%s ignored! (unimplemented)", UnDefines[index]);
  584.     **************************/
  585.     }
  586.     AddToCommand(" -d%s", "LATTICE");    /* Make sure LATTICE is defined */
  587.     for (index = 0; index <NDefines; index++) {
  588.     AddToCommand (" -d%s", Defines[index]);
  589.     }
  590.     if (!sdflag) AddToCommand (" -%s", "b0");    /* Small code */
  591.     if (gflag) AddToCommand (" -%c", 'd');    /* Debug */
  592.     if (!protoflag) AddToCommand(" -c%c", 'f');    /* no missing proto warnings */
  593.     if (!sourceflag) AddToCommand(" -c%c", 'e');/* turn on source listings */
  594.     if (FFPflag) AddToCommand(" -%c", 'f');    /* FFP floating point */
  595.     if (shortflag) AddToCommand(" -%c", 'w');    /* Short integers */
  596.     /* Turn off output noise, turn on more checking */
  597.     AddToCommand (" %s", "-ct -c+ -.") ;
  598.     AddToCommand (" %s", op -> Rootname);
  599.     status = RunCommand ();
  600.     DBUG_RETURN (status);
  601. }
  602.  
  603. /*
  604.  *    Run second pass of compiler on a single operand.
  605.  */
  606.  
  607. static int
  608. Pass2 (op) struct Operand *op;
  609. {
  610.     int status;
  611.     
  612.     DBUG_ENTER ("Pass2");
  613.     CHECKABORT;
  614.     InitCommand ();
  615.     AddToCommand ("%s", Locate ("lc2", BinDirs));
  616.     AddToCommand (" -. -o%s.o", op -> Basename);
  617.     if (!scflag) AddToCommand (" -%s", "r0");
  618.     if (Avflag) AddToCommand (" -%c", 'v');
  619.     if (ABflag || ACflag || ADflag)
  620.         AddToCommand (" -c%s%s%s",        /* Ugly, but... */
  621.         ABflag ? "b" : "",
  622.         ACflag ? "c" : "",
  623.         ADflag ? "d" : "") ;
  624.     if (Ayflag) AddToCommand(" -%c", 'y');    /* Load A6 for the user */
  625.     AddToCommand (" %s%s", QuadDev, op -> Basename);
  626.     status = RunCommand ();
  627.     DBUG_RETURN (status);
  628. }
  629.  
  630. /*
  631.  *    I have not yet had occasion to use the macro assembler, so this
  632.  *    part is not yet implemented.  If anyone wants to send me the
  633.  *    appropriate code, I will be glad to install it.
  634.  */
  635.  
  636. static void
  637. Assemble (op) struct Operand *op;
  638. {
  639.     DBUG_ENTER ("Assemble");
  640.     CHECKABORT;
  641.     Warning ("assembly pass not yet implemented");
  642.     ErrCount++;
  643.     DBUG_VOID_RETURN;
  644. }
  645.  
  646. /*
  647.  *    As far as I can tell, the child status is not returned, only
  648.  *    whether or not the child could be run.  So, how do we find out
  649.  *    whether there was an error or not?  It's probably in the manuals
  650.  *    somewhere, I just haven't had time to dig yet.
  651.  *
  652.  *    Note that because Lattice printf is not capable of printing more
  653.  *    than 200 characters at a time, we must spit them out one at a time
  654.  *    to make sure the entire command line gets printed when -V is used.
  655.  *
  656.  */
  657.  
  658. static int
  659. RunCommand (void)
  660. {
  661.     int status;
  662.     register char *cmdp;
  663.     
  664.     DBUG_ENTER ("RunCommand");
  665.     DBUG_3 ("cmd", "execute '%s'", Command);
  666.     if (Vflag) {
  667.     for (cmdp = Command; *cmdp != '\000'; cmdp++) {
  668.         putchar (*cmdp);                /* see above */
  669.     }
  670.     putchar ('\n');
  671.     (void) fflush (stdout);
  672.     }
  673.     status = system (Command);
  674.     DBUG_3 ("sys", "subcommand returns status %d", status);
  675.     if (status) {
  676.     ErrCount++;
  677.     }
  678.     DBUG_RETURN (status);
  679. }
  680.  
  681. /*
  682.  *    Look through the list of paths pointed to by "vec" until we find
  683.  *    a file with name given pointed to by "namep".  If none is found,
  684.  *    the name pointed to by namep is returned.
  685.  */
  686.  
  687. static char *
  688. Locate (namep, vec)
  689.     char *namep, **vec;
  690. {
  691.     static char namebuf[ARGSIZE];
  692.     
  693.     DBUG_ENTER ("Locate");
  694.     while (*vec != NULL) {
  695.     (void) sprintf (namebuf, "%s%s", *vec, namep);
  696.     DBUG_3 ("try", "look for '%s'", namebuf);
  697.     if (Readable (namebuf)) {
  698.         namep = namebuf;
  699.         break;
  700.     }
  701.     vec++;
  702.     }
  703.     DBUG_RETURN (namep);
  704. }
  705.  
  706. /*
  707.  *    Check to see if the file exists and is readable.
  708.  */
  709.  
  710. #include <libraries/dos.h>
  711.  
  712. static int
  713. Readable (name) char *name;
  714. {
  715.     register int status = 0;
  716.     register int fildes;
  717.     
  718.     DBUG_ENTER ("Readable");
  719. #ifdef unix
  720.     fildes = open (name, O_RDONLY);
  721.     if (fildes >= 0) {
  722.     (void) close (fildes);
  723.     status = 1;
  724.     }
  725. #else
  726.     fildes = Lock (name, ACCESS_READ);
  727.     if (fildes != 0) {
  728.         UnLock (fildes);
  729.     status = 1;
  730.     }
  731. #endif
  732.     DBUG_RETURN (status);
  733. }
  734.  
  735. /*
  736.  *    Initialize the command line buffer and associated variables to
  737.  *    discard any previous command line.
  738.  */
  739.  
  740. static void
  741. InitCommand (void)
  742. {
  743.     Command[0] = '\000';
  744.     EndCommand = Command;
  745. }
  746.  
  747. /*
  748.  *    Build string to add to end of current command line, checking
  749.  *    for overflow in the command buffer and maintaining the pointer
  750.  *    to the end of the current command.
  751.  *
  752.  *    Note that we are a "printf type" of command, and can be called
  753.  *    with up to three "char *" arguments.  There is a portability
  754.  *    problem here, but Lattice hasn't yet made "varargs" a standard
  755.  *    part of their distribution.
  756.  *
  757.  *    Also, note that the return argument of sprintf is supposed to be
  758.  *    the number of characters to be added to the buffer.  This is
  759.  *    not always true for some C implementations.  In particular,
  760.  *    sprintf in BSD4.1 returns a pointer.  Thus we don't use the
  761.  *    return argument.
  762.  *
  763.  */
  764.  
  765. /*VARARGS1*/
  766. static void
  767. AddToCommand (fmt, arg1, arg2, arg3)
  768. char *fmt;
  769. char *arg1, *arg2, *arg3;
  770. {
  771.     register int length;
  772.     auto char buffer[ARGSIZE];
  773.  
  774.     (void) sprintf (buffer, fmt, arg1, arg2, arg3);
  775.     length = strlen (buffer);
  776.     if ((EndCommand - Command) + length >= sizeof (Command)) {
  777.     Fatal ("command line too long (%d char max)", sizeof (Command));
  778.     } else {
  779.     (void) strcat (EndCommand, buffer);
  780.     EndCommand += length;
  781.     }
  782. }
  783.  
  784. /*
  785.  *    If an executable is made from a single C file, the normal behavior
  786.  *    for the unix environment is to treat the .o file as an intermediate
  787.  *    file and remove it, so we follow suit.
  788.  */
  789.  
  790. static void
  791. CleanObjects (void)
  792. {
  793.     auto char buffer[ARGSIZE];
  794.     register struct Operand *op;
  795.     
  796.     DBUG_ENTER ("CleanObjects");
  797.     if (NOperands == 1) {
  798.     op = &Operands[0];
  799.     if (CFILE (op) || SFILE (op)) {
  800.         sprintf (buffer, "%s.o", op -> Basename);
  801.         if (!DeleteFile (buffer)) {
  802.         Warning ("can't delete '%s'", buffer);
  803.         }
  804.     }
  805.     }
  806.     DBUG_VOID_RETURN;